WPF Diagrams includes built-in visual styles for shapes and for flow and star diagrams. To use a built-in visual style, set DiagramSurface.Formatter to the resource identified by the appropriate key. For example:
CopyXML
<ms:DiagramSurface Formatter="{StaticResource {x:Static ms:FlowDiagramStyles.GradientStyleFormatterKey}}" />

(A suitable formatter for shapes is used by default and does not need to be specified.)

You will usually need to customise node visuals at the Foundation level only if you want to use a new node type which is not defined in the core package. In this case there are two steps: define a new style, and hook up a style selector to specify when to use the new style.

If you are creating your own shapes, but you are still using ShapeNode, you do not need to create a special style for them.
 

Defining the Style for a New Node Type

The Style you define will be applied to a DiagramNodeElement. The framework ensures that the element is instantiated at the correct position on the DiagramSurface and with the correct size, as specified by the Bounds property.

In most cases, the only property you need to set in your Style is the NodeTemplate property. This should be set to a DataTemplate which describes how you want to render the node and its data.

If your template is a simple shape such as a Rectangle, Ellipse or Border, it will size automatically. If you are using a more complex shape such as a Path, you should use the Bounds property to determine the location of points on the path.

A typical template consists of a background shape with a text box and/or other controls on top of it. By default, all of these elements are “live”—that is, the user can interact with them as normal, and mouse activity over these elements is not translated into a drag-move. Any element which is not intended to be “live,” and which the user should therefore be able to use for dragging, must have its IsHitTestVisible property set to false, so that mouse activity can be passed on to the underlying MoveThumb. Typically, you should set IsHitTestVisible to false on the background shape, but not on any of the foreground controls.

You can choose content controls explicitly, for example, by specifying a TextBox or Button control as part of your template, or delegate back to the DiagramFormatter’s NodeContentTemplateSelector. The default content template is a text box but you can create a selector that allows you to present different kinds of node content consistently across different node types/styles.

Other properties you may wish to style include ConnectionPointPositions, which specifies where on the shape the connection points should appear.

The first example shows a style which defines a custom shape and custom connection point positions, but displays the node data using the default template (typically a text box in which the user can edit the node data).

CopyCustom style using default content display and customising connection point positions
<Style TargetType="ms:DiagramNodeElement">
  <Setter Property="ConnectionPointPositions" Value="L 0.2,0.5" />
  <Setter Property="NodeTemplate">
    <Setter.Value>
      <DataTemplate>
        <Grid>
          <Path Stroke="CadetBlue" StrokeThickness="1" 
                Fill="AliceBlue" ms:DiagramNodeElement.IsGeometryProvider="True" 
                IsHitTestVisible="False" Stretch="Fill" 
                Data="M 0 0 L 0.8 0 L 1 0.5 L 0.8 1 L 0 1 L 0.2 0.5 Z" />
          <ContentPresenter Content="{Binding}" 
                            ContentTemplateSelector="{Binding NodeContentTemplateSelector, RelativeSource={RelativeSource AncestorType={x:Type ms:DiagramNodeElement}}}" />
        </Grid>
      </DataTemplate>
    </Setter.Value>
  </Setter>
</Style>

The second example shows a style where the node background comprises a simple ellipse, but instead of editing the node data using a text box the style specifies a read-only display and a pair of up-down buttons. This would be suitable for displaying numeric content.

CopyCustom style using its own controls to display and edit content
<Style TargetType="ms:DiagramNodeElement">
  <Setter Property="NodeTemplate">
    <Setter.Value>
      <DataTemplate>
        <Grid>
          <Grid.RowDefinitions>
            <RowDefinition Height="*" />
            <RowDefinition Height="Auto" />
            <RowDefinition Height="*" />
          </Grid.RowDefinitions>
          <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*" />
            <ColumnDefinition Width="Auto" />
            <ColumnDefinition Width="*" />
          </Grid.ColumnDefinitions>
          <Ellipse Stroke="CadetBlue" StrokeThickness="1" Fill="AliceBlue" 
                   IsHitTestVisible="False" 
                   Grid.RowSpan="3" Grid.ColumnSpan="3" />
          <TextBlock Text="{Binding Data}" 
                     FontSize="20" LineHeight="20" 
                     Grid.Row="1" Grid.Column="1" 
                     VerticalAlignment="Center" Margin="0,2,0,6" />
          <RepeatButton FontSize="8" Grid.Row="0" Grid.Column="1" Style="{StaticResource FlatButton}" 
                        HorizontalAlignment="Center" VerticalAlignment="Bottom" Click="UpButton_Click" Tag="{Binding}">
            <Polygon Points="0,6 6,0 12,6" Fill="CadetBlue" />
          </RepeatButton>
          <RepeatButton FontSize="8" Grid.Row="2" Grid.Column="1" Style="{StaticResource FlatButton}" 
                        HorizontalAlignment="Center" VerticalAlignment="Top" Click="DownButton_Click" Tag="{Binding}">
            <Polygon Points="0,0 6,6 12,0" Fill="CadetBlue" />
          </RepeatButton>
        </Grid>
      </DataTemplate>
    </Setter.Value>
  </Setter>
</Style>

Selecting the New Style

To add the Style to the formatter, you must first create a StyleSelector to load your template. You will typically do this by instantiating a MatchingStyleSelector, or TypeStyleSelector and adding a TypeStyle that references your node type and your style. In order to continue to use the style default templates for other node types, set the DelegatingDataTemplateSelector.BasedOn property to the built-in style identified by the NodeStyleSelectorKey for the built-in style you want. For example:
CopyXML
<ms:MatchingStyleSelector x:Key="NodeStyleSelector" BasedOn="{StaticResource {x:Static ms:GradientStyle.NodeStyleSelectorKey}}">
  <ms:TypeStyle DataType="local:SendMessageNode" Style="{StaticResource SendMessageNodeStyle}" />
  <ms:TypeStyle DataType="local:WaitNode" Style="{StaticResource WaitNodeStyle}" />
</ms:MatchingStyleSelector>

You must then create an instance of IDiagramFormatter whose NodeTemplateSelector is set to your DataTemplateSelector. Other properties can be set to the style defaults. For example:

CopyHooking up the style selector
<Window.Resources>
  <ms:DiagramFormatter x:Key="Formatter" 
                       NodeStyleSelector="{StaticResource NodeStyleSelector}" 
                       />
</Window.Resources>

<ms:DiagramSurface Formatter="{StaticResource Formatter}" />

Additional Considerations

If your connection points are interior to the bounding rectangle (because the node does not occupy the entire rectangle), you should specify the DiagramNodeElement.IsGeometryProvider on the element which defines the node outline. Otherwise, the entire bounding rectangle will be draggable to move the node, and users will not be able to drag connections off connection points in order to relocate them.

For a worked example, please refer to the CustomStyle.FlowDiagrams sample.